package es.us.lsi.daw.dao.impl;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.annotation.Transactional;

import es.us.lsi.daw.dao.DAOAuthentication;
import es.us.lsi.daw.dao.DAOPaginacion;
import es.us.lsi.daw.model.security.User;
import es.us.lsi.daw.model.util.BaseEntity;


public class DAOPaginacionImpl extends DAOComunImpl implements DAOPaginacion {

	@Autowired
	DAOAuthentication daoAuthentication;
	
	/****************************************************************************************************************/
	/****************************************** MÉTODOS GENERALES ***************************************************/
	/****************************************************************************************************************/

	public <T> List<T> getListaClasePaginacion(Class<T> clase, Long page) {

		return getListaClasePaginacion(clase, page, null);
	}

	public <T> List<T> getListaClasePaginacion(Class<T> clase, Long page, String lista) throws DataAccessException {

		return getListaClasePaginacion(clase, page, lista, null);
	}

	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	public <T> List<T> getListaClasePaginacion(Class<T> clase, Long page, String lista, Integer numMaxRegistros) throws DataAccessException {

		Order orden = null;
		Criteria crtResultados = null;
		List<T> lstResultado = null;
		try {
			orden = ((BaseEntity) clase.newInstance()).getOrder();
		} catch (Exception e) {
		}

		if (numMaxRegistros == null) {
			numMaxRegistros = DAOComunImpl.PAGE_SIZE;
		}

		Criteria crtId = sessionFactory.getCurrentSession().createCriteria(clase);
		crtId.setMaxResults(numMaxRegistros).setFirstResult(numMaxRegistros * (page.intValue() - 1));
		crtId.setProjection(Projections.distinct(Projections.property(BaseEntity.A_ID)));
		if (orden != null) {
			crtId.addOrder(orden);
		}
		List<Long> lstIds = crtId.list();

		if (!lstIds.isEmpty()) {
			crtResultados = sessionFactory.getCurrentSession().createCriteria(clase);
			crtResultados.add(Restrictions.in(BaseEntity.A_ID, lstIds));
			if (lista != null && !lista.isEmpty()) {
				crtResultados.setFetchMode(lista, FetchMode.JOIN).setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
			}

			if (orden != null) {
				crtResultados.addOrder(orden);
			}

			lstResultado = crtResultados.list();
		} else {
			lstResultado = new ArrayList<T>();
		}

		return lstResultado;
	}

	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	public <T> List<T> getListaClasePaginacionOrdenada(Class<T> clase, Long page, String atributo) throws DataAccessException {

		Criteria crtConsulta = sessionFactory.getCurrentSession().createCriteria(clase);
		crtConsulta.addOrder(Order.desc(atributo));
		crtConsulta.setMaxResults(PAGE_SIZE).setFirstResult(PAGE_SIZE * (page.intValue() - 1));
		return crtConsulta.list();
	}

	@Transactional(readOnly = true)
	public <T> Long getSizeClase(Class<T> clase) throws DataAccessException {

		List<?> lst = sessionFactory.getCurrentSession().createCriteria(clase).setProjection(Projections.rowCount()).list();
		Long i = new Long(0);
		if (!lst.isEmpty())
			i = (Long) lst.get(0);
		return i;
	}
	
	@Deprecated //TODO name and surname are now in WebUser
	public long obtenerTamFiltroListUser(String nombre, String apellidos) {

		Long result = 0l;
		Criteria crtTam = null;
		List<?> lstTam = null;
		crtTam = sessionFactory.getCurrentSession().createCriteria(User.class);

		if (nombre != null && !nombre.isEmpty()) {
//			crtTam.add(Restrictions.ilike(User.A_NOMBRE, nombre, MatchMode.ANYWHERE));
		}
		if (apellidos != null && !apellidos.isEmpty()) {
//			crtTam.add(Restrictions.ilike(User.A_APELLIDOS, apellidos, MatchMode.ANYWHERE));
		}
		crtTam.add(Restrictions.eq(User.A_ENABLED, true));
		if (crtTam != null) {
			lstTam = crtTam.setProjection(Projections.rowCount()).list();
			if (!lstTam.isEmpty()) {
				result = (Long) lstTam.get(0);
			}
		}

		return result;
	}

	@Deprecated //TODO name and surname are now in WebUser
	public List<?> filtrarListUser(String nombre, String apellidos, Long numPagina, Integer numMaxRegistros) {

		List<?> result = null;
		Criteria crtUser = null;
		crtUser = sessionFactory.getCurrentSession().createCriteria(User.class);
		crtUser.add(Restrictions.eq(User.A_ENABLED, true));
		if (nombre != null && !nombre.isEmpty()) {
//			crtUser.add(Restrictions.ilike(User.A_NOMBRE, nombre, MatchMode.ANYWHERE));
		}

		if (apellidos != null && !apellidos.isEmpty()) {
//			crtUser.add(Restrictions.ilike(User.A_APELLIDOS, apellidos, MatchMode.ANYWHERE));
		}

		if (crtUser != null) {
			crtUser.setFetchMode(User.A_GROUPS, FetchMode.JOIN);
			crtUser.setMaxResults(numMaxRegistros).setFirstResult(numMaxRegistros * (numPagina.intValue() - 1));
			crtUser.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
			result = crtUser.list();
		}

		if (result == null) {
			result = new ArrayList<User>();
		}

		return result;
	}

	public Long getSizeUser(Class<User> clase) {
		Criteria crt = sessionFactory.getCurrentSession().createCriteria(clase);
		crt.add(Restrictions.eq(User.A_ENABLED, true));
		crt.setProjection(Projections.rowCount());
		List<?> lst = crt.list();
		Long i = new Long(0);
		if (!lst.isEmpty())
			i = (Long) lst.get(0);
		return i;
	}

	public List<User> getListaClasePaginacionUser(Class<User> clase, Long numPagina, String lista, Integer numMaxRegistros) {
		Order orden = null;
		Criteria crtResultados = null;
		List<User> lstResultado = null;
		try {
			orden = ((BaseEntity) clase.newInstance()).getOrder();
		} catch (Exception e) {
		}

		if (numMaxRegistros == null) {
			numMaxRegistros = DAOComunImpl.PAGE_SIZE;
		}

		Criteria crtId = sessionFactory.getCurrentSession().createCriteria(clase);

		crtId.setMaxResults(numMaxRegistros).setFirstResult(numMaxRegistros * (numPagina.intValue() - 1));
		crtId.setProjection(Projections.distinct(Projections.property("id")));
		crtId.add(Restrictions.eq(User.A_ENABLED, true));
		if (orden != null) {
			crtId.addOrder(orden);
		}
		List<Long> lstIds = crtId.list();

		if (!lstIds.isEmpty()) {
			crtResultados = sessionFactory.getCurrentSession().createCriteria(clase);
			crtResultados.add(Restrictions.in(User.A_ID, lstIds));
			if (lista != null && !lista.isEmpty()) {
				crtResultados.setFetchMode(lista, FetchMode.JOIN).setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
			}

			if (orden != null) {
				crtResultados.addOrder(orden);
			}

			lstResultado = crtResultados.list();
		} else {
			lstResultado = new ArrayList<User>();
		}

		return lstResultado;
	}

}
